#include "Font.h"
#include "Stream.h"

#include "zlib.h"
#include "LightAbstractRenderer.h"
#include "TagList.h"
#include "CharacterList.h"
#include "Shape.h"

namespace LightPlayer{

	// FontInfo

	void FontInfo::init(){
		m_FontName = s_empty_string;
		m_NameMemory.clear();
		m_CodeTable.clear();
		m_LanguageCode = 0;

		m_flag_small_text = false;
		m_flag_shift_JIS = false;
		m_flag_ANSI = false;
		m_flag_italic = false;
		m_flag_bold = false;
		m_flag_wide_code = false;
	}

	void FontInfo::readFromStream( Stream* stream, const TAG& actual_tag, int glyph_number ){
		init();

		uint8 FontNameLen = stream->read_u8();
		m_NameMemory.resize( FontNameLen );
		memcpy( &(m_NameMemory[0]), stream->getCurrentPosition(), FontNameLen );
		stream->skip_byte( FontNameLen );

		m_FontName = (const char*)( &(m_NameMemory[0]) );

		bool reserved = true;
		reserved = stream->read_bool(); // skip 2 bits
		reserved = stream->read_bool();

		m_flag_small_text = stream->read_bool();
		m_flag_shift_JIS = stream->read_bool();
		m_flag_ANSI = stream->read_bool();
		m_flag_italic = stream->read_bool();
		m_flag_bold = stream->read_bool();
		m_flag_wide_code = stream->read_bool();

		if( actual_tag.type == eDefineFontInfo2 ){
			m_LanguageCode = stream->read_u8();
		}

		m_CodeTable.reserve(glyph_number);
		for (int i=0; i<glyph_number; ++i){
			m_CodeTable.push_back( m_flag_wide_code ? stream->read_u16() : stream->read_u8() );
		}
	}



	// Font

	Font::Font(){
		init();
	}

	Font::~Font(){
		init();
	}

	void Font::init(){
		m_CharacterId = 0;
		m_pCharacterList = NULL;
		m_Info.init();
	}

	void Font::readFromStream( Stream* stream, const TAG& actual_tag, CharacterList* pCharacterList /*= NULL*/ ){
		init();

		if( actual_tag.type == eDefineFont ){
			Stream GlyphStream( stream->getCurrentPosition(), stream->getBufferSize() - stream->getCurrentOffset() );
			stream->skip_byte( actual_tag.size - 2 );

			m_pCharacterList = pCharacterList;

			array<uint16> offsetTable;
			offsetTable.push_back( GlyphStream.read_u16() );
			int glyphs_number = offsetTable.back() / 2;
		
			for (int i=1; i<glyphs_number; i++){
				offsetTable.push_back( GlyphStream.read_u16() );
			}

			for (int i=0; i<glyphs_number; i++){
				GlyphStream.gotoOffset( offsetTable[i] );

				Shape* new_shape = m_pCharacterList->createShapeDef();
				new_shape->readFromStream( &GlyphStream , actual_tag.type, pCharacterList, true );
				m_Glyphs.push_back( new_shape );
			}
		}
		else if( actual_tag.type == eDefineFont2 ){
			m_Info.init();

			bool flag_has_layout = stream->read_bool();
			m_Info.m_flag_shift_JIS = stream->read_bool(); 
			m_Info.m_flag_small_text = stream->read_bool();
			m_Info.m_flag_ANSI = stream->read_bool(); 
			bool WideOffset = stream->read_bool(); 
			m_Info.m_flag_wide_code = stream->read_bool(); 
			m_Info.m_flag_italic = stream->read_bool(); 
			m_Info.m_flag_bold = stream->read_bool(); 

			m_Info.m_LanguageCode = stream->read_u8();

			// Start Name
			uint8 FontNameLen = stream->read_u8();
			m_Info.m_NameMemory.resize( FontNameLen );
			memcpy( &(m_Info.m_NameMemory[0]), stream->getCurrentPosition(), FontNameLen );
			stream->skip_byte( FontNameLen );
			m_Info.m_FontName = (const char*)( &(m_Info.m_NameMemory[0]) );
			// End Name


			// Start Glyphs Shape
			int glyphs_number = stream->read_u16(); 

			Stream GlyphStream( stream->getCurrentPosition(), stream->getBufferSize() - stream->getCurrentOffset() );
			m_pCharacterList = pCharacterList;

			array<uint16> offsetTable;
			for (int i=0; i<glyphs_number; i++){
				offsetTable.push_back( WideOffset ? GlyphStream.read_u32() : GlyphStream.read_u16() );
			}
			for (int i=0; i<glyphs_number; i++){
				GlyphStream.gotoOffset( offsetTable[i] );

				Shape* new_shape = m_pCharacterList->createShapeDef();
				new_shape->readFromStream( &GlyphStream , actual_tag.type, pCharacterList, true );
				m_Glyphs.push_back( new_shape );
			}
			GlyphStream.align(); // useful ???

			stream->skip_byte( GlyphStream.getCurrentOffset() );
			// End Glyphs Shape


			m_Info.m_CodeTable.reserve(glyphs_number);
			for (int i=0; i<glyphs_number; ++i){
				m_Info.m_CodeTable.push_back( m_Info.m_flag_wide_code ? stream->read_u16() : stream->read_u8() );
			}

			if( flag_has_layout ){ 
				/// !!!! SKIP ALL LAYOUT !!! ////
				// should be manage later if we want this feature ...
				uint16 font_ascent = stream->read_u16(); 
				uint16 font_desent = stream->read_u16(); 
				int16 font_leading = stream->read_s16(); 
				for (int i=0; i<glyphs_number; i++){
					int16 advance_table = stream->read_s16();
				}
				for (int i=0; i<glyphs_number; i++){
					RECT rect;
					rect.readFromStream( stream );
				}
				int kerning_count = stream->read_u16(); 
				for (int i=0; i<kerning_count; i++){
					uint16 kerning_code_1 = m_Info.m_flag_wide_code ? stream->read_u16() : stream->read_u8();
					uint16 kerning_code_2 = m_Info.m_flag_wide_code ? stream->read_u16() : stream->read_u8();
					int16 kerning_adjustment =stream->read_s16(); 
				}
			}
		}
	}

};